

#ifndef  __MESH_MODEL_H
#define  __MESH_MODEL_H


#include <vcg/complex/algorithms/update/color.h>
#include <vcg/complex/algorithms/create/mc_trivial_walker.h>


#ifndef MESHLAB_SCALAR
#error "Fatal compilation error: MESHLAB_SCALAR must be defined"
#endif

typedef MESHLAB_SCALAR Scalarm;
typedef vcg::Point2<MESHLAB_SCALAR>   Point2m;
typedef vcg::Point3<MESHLAB_SCALAR>   Point3m;
typedef vcg::Point4<MESHLAB_SCALAR>   Point4m;
typedef vcg::Plane3<MESHLAB_SCALAR>   Plane3m;
typedef vcg::Segment2<MESHLAB_SCALAR> Segment2m;
typedef vcg::Segment3<MESHLAB_SCALAR> Segment3m;
typedef vcg::Box3<MESHLAB_SCALAR>     Box3m;
typedef vcg::Matrix44<MESHLAB_SCALAR> Matrix44m;
typedef vcg::Matrix33<MESHLAB_SCALAR> Matrix33m;
typedef vcg::Shot<MESHLAB_SCALAR>     Shotm;
typedef vcg::SimpleVoxel<MESHLAB_SCALAR> SimpleVoxelm;
typedef vcg::Similarity<MESHLAB_SCALAR> Similaritym;

namespace vcg
{
	namespace vertex
	{
		template <class T> class Coord3m: public Coord<vcg::Point3<MESHLAB_SCALAR>, T> 
		{
		public:	static void Name(std::vector<std::string> & name){name.push_back(std::string("Coord3m"));T::Name(name);}
		};

		template <class T> class Normal3m: public Normal<vcg::Point3<MESHLAB_SCALAR>, T> 
		{
		public:	static void Name(std::vector<std::string> & name){name.push_back(std::string("Normal3m"));T::Name(name);}
		};

		template <class T> class CurvatureDirmOcf: public CurvatureDirOcf<CurvatureDirTypeOcf<MESHLAB_SCALAR>, T> 
		{
		public:	static void Name(std::vector<std::string> & name){name.push_back(std::string("CurvatureDirmOcf"));T::Name(name);}
		};

		template <class T> class RadiusmOcf: public RadiusOcf<MESHLAB_SCALAR, T> 
		{
		public:	static void Name(std::vector<std::string> & name){name.push_back(std::string("RadiusmOcf"));T::Name(name);}
		};

	}//end namespace vertex
	namespace face
	{
		template <class T> class Normal3m: public NormalAbs<vcg::Point3<MESHLAB_SCALAR>, T> 
		{
		public:  static void Name(std::vector<std::string> & name){name.push_back(std::string("Normal3m"));T::Name(name);}
		};

		template <class T> class CurvatureDirmOcf: public CurvatureDirOcf<CurvatureDirOcfBaseType<MESHLAB_SCALAR>, T> 
		{
		public:	static void Name(std::vector<std::string> & name){name.push_back(std::string("CurvatureDirdOcf"));T::Name(name);}
		};

	}//end namespace face
}//end namespace vcg



// Forward declarations needed for creating the used types
class CVertexO;
class CEdgeO;
class CFaceO;

// Declaration of the semantic of the used types
class CUsedTypesO: public vcg::UsedTypes < vcg::Use<CVertexO>::AsVertexType,
	vcg::Use<CEdgeO   >::AsEdgeType,
	vcg::Use<CFaceO  >::AsFaceType >
{
};


// The Main Vertex Class
// Most of the attributes are optional and must be enabled before use.
// Each vertex needs 40 byte, on 32bit arch. and 44 byte on 64bit arch.

class CVertexO  : public vcg::Vertex< CUsedTypesO,
	vcg::vertex::InfoOcf,           /*  4b */
	vcg::vertex::Coord3m,           /* 12b */
	vcg::vertex::BitFlags,          /*  4b */
	vcg::vertex::Normal3m,          /* 12b */
	vcg::vertex::Qualityf,          /*  4b */
	vcg::vertex::Color4b,           /*  4b */
	vcg::vertex::VFAdjOcf,          /*  0b */
	vcg::vertex::MarkOcf,           /*  0b */
	vcg::vertex::TexCoordfOcf,      /*  0b */
	vcg::vertex::CurvaturefOcf,     /*  0b */
	vcg::vertex::CurvatureDirmOcf,  /*  0b */
	vcg::vertex::RadiusmOcf         /*  0b */
>
{
};


// The Main Edge Class
class CEdgeO : public vcg::Edge<CUsedTypesO,
	vcg::edge::BitFlags,          /*  4b */
	vcg::edge::EVAdj,
	vcg::edge::EEAdj
>
{
};

// Each face needs 32 byte, on 32bit arch. and 48 byte on 64bit arch.
class CFaceO    : public vcg::Face<  CUsedTypesO,
	vcg::face::InfoOcf,              /* 4b */
	vcg::face::VertexRef,            /*12b */
	vcg::face::BitFlags,             /* 4b */
	vcg::face::Normal3m,             /*12b */
	vcg::face::QualityfOcf,          /* 0b */
	vcg::face::MarkOcf,              /* 0b */
	vcg::face::Color4bOcf,           /* 0b */
	vcg::face::FFAdjOcf,             /* 0b */
	vcg::face::VFAdjOcf,             /* 0b */
	vcg::face::CurvatureDirmOcf,     /* 0b */
	vcg::face::WedgeTexCoordfOcf     /* 0b */
> 
{
};


class CMeshO    : public vcg::tri::TriMesh< vcg::vertex::vector_ocf<CVertexO>, vcg::face::vector_ocf<CFaceO> >
{
public :
	int sfn;    //The number of selected faces.
	int svn;    //The number of selected vertices.
	Matrix44m Tr; // Usually it is the identity. It is applied in rendering and filters can or cannot use it. (most of the filter will ignore this)

	double dPCAValue[ 3 ];
	//double	dPCARatio;		//Add by lxj on 2016-1-21 for improve the Match precise

	const Box3m &trBB()
	{
		static Box3m bb;
		bb.SetNull();
		bb.Add(Tr,bbox);
		return bb;
	}

	//Add by lxj on 2016-1-21
	inline bool IsPCA_Correspond( const CMeshO& m )
	{
		return ( fabs( dPCAValue[ 0 ] / dPCAValue[ 2 ] - m.dPCAValue[ 0 ] / m.dPCAValue[ 2 ] ) < 0.01 ) &&
			( fabs( dPCAValue[ 1 ] / dPCAValue[ 2 ] - m.dPCAValue[ 1 ] / m.dPCAValue[ 2 ] ) < 0.01 );
	}
};



class CMeshModel
{
public:
	/*
	This enum specify the various simplex components
	It is used in various parts of the framework:
	- to know what elements are currently active and therefore can be saved on a file
	- to know what elements are required by a filter and therefore should be made ready before starting the filter (e.g. if a
	- to know what elements are changed by a filter and therefore should be saved/restored in case of dynamic filters with a preview
	*/
	enum MeshElement
	{
		MM_NONE             = 0x00000000,
		MM_VERTCOORD        = 0x00000001,
		MM_VERTNORMAL       = 0x00000002,
		MM_VERTFLAG         = 0x00000004,
		MM_VERTCOLOR        = 0x00000008,
		MM_VERTQUALITY      = 0x00000010,
		MM_VERTMARK	        = 0x00000020,
		MM_VERTFACETOPO     = 0x00000040,
		MM_VERTCURV	        = 0x00000080,
		MM_VERTCURVDIR      = 0x00000100,
		MM_VERTRADIUS       = 0x00000200,
		MM_VERTTEXCOORD     = 0x00000400,
		MM_VERTNUMBER       = 0x00000800,

		MM_FACEVERT         = 0x00001000,
		MM_FACENORMAL       = 0x00002000,
		MM_FACEFLAG	        = 0x00004000,
		MM_FACECOLOR        = 0x00008000,
		MM_FACEQUALITY      = 0x00010000,
		MM_FACEMARK	        = 0x00020000,
		MM_FACEFACETOPO     = 0x00040000,
		MM_FACENUMBER       = 0x00080000,
		MM_FACECURVDIR      = 0x00100000,

		MM_WEDGTEXCOORD     = 0x00200000,
		MM_WEDGNORMAL       = 0x00400000,
		MM_WEDGCOLOR        = 0x00800000,

		// 	Selection
		MM_VERTFLAGSELECT   = 0x01000000,
		MM_FACEFLAGSELECT   = 0x02000000,

		// Per Mesh Stuff....
		MM_CAMERA			= 0x08000000,
		MM_TRANSFMATRIX     = 0x10000000,
		MM_COLOR            = 0x20000000,
		MM_POLYGONAL        = 0x40000000,
		MM_UNKNOWN          = 0x80000000,

		MM_ALL				= 0xffffffff
	};


public:
	CMeshModel( const char* fullFileName = 0, const char* labelName = 0 );


public:
	void Clear();

	void Enable(int openingFileMask);

	bool HasDataMask(const int maskToBeTested) const;

	void UpdateDataMask( CMeshModel *m );

	void UpdateDataMask(int neededDataMask);

	void ClearDataMask(int unneededDataMask);

	static int io2mm(int single_iobit);

public:
	CMeshO cm;

private:
	int currentDataMask;
	std::string fullPathFileName;
	std::string _label;
	int _id;
	bool modified;
};// end class MeshModel


#endif  //__MESH_MODEL_H